//using UnityEngine;
using System;
using System.Collections;
using System.Net;
using System.Net.Sockets;

namespace MxNetwork
{
    public class MxNwkListenerDesc
    {
        public MxNwkListenerDesc(string IP, int Port, bool IsEncrypt, uint LocalType, uint LocalID)
        {
            m_IP = IP;
            m_Port = Port;
            m_IsEncrypt = IsEncrypt;
            m_LocalType = LocalType;
            m_LocalID = LocalID;            
        }

        public string m_IP;
        public int m_Port;
        public bool m_IsEncrypt;
        public uint m_LocalType;
        public uint m_LocalID;
    }

    public class MxNwkListener : IDisposable
    {
        const int LISTENER_NUM = 5000;

        public MxNwkListener()
        {
            m_onAccepted = new AsyncCallback(AcceptEnd);
        }       
        
        public virtual bool Create(MxNwkListenerDesc Desc, MxNwkObsListener ObsListener, MxNwkObsChannel ObsChannel)
        {
            m_Desc = Desc;
            m_ObsListener = ObsListener;
            m_ObsChannel = ObsChannel;
            IPAddress ip = IPAddress.Parse(m_Desc.m_IP);
            IPEndPoint ipe = new IPEndPoint(ip, m_Desc.m_Port);

            try
            {                
                m_sockListener = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
                m_sockListener.Bind(ipe);
                m_sockListener.Listen(LISTENER_NUM);
            }
            catch(SocketException)
            {
                Console.WriteLine("Can't open {0}!", ipe.ToString());
                m_ObsListener.OnListenFailed();
                return false;
            }

            Console.WriteLine("Start listen {0}!", ipe.ToString());

            for(int i=0; i<LISTENER_NUM; ++i)
            {
                PostAccept();
            }

            return true;
        }
  
        private void AcceptEnd(IAsyncResult asyncResult)
        {            
            PostAccept();

            try {
                Socket socket = m_sockListener.EndAccept(asyncResult);    
                MxNwkChannelDesc descChl = new MxNwkChannelDesc();	
    		    descChl.hChannel = MxNetworkManager.GetInstance().AssignChannelHandle();
                descChl.Sock = socket;
                descChl.Remote = new MxNwkAddressIP((socket.RemoteEndPoint as IPEndPoint).Address.ToString());
    		    CreateChannel(descChl);            
            }
            catch(SocketException e)
            {
                Console.WriteLine("SocketException: {0}!", e);
            }
        }

        private void PostAccept()
        {
            m_sockListener.BeginAccept(0, m_onAccepted, null);
        }

        public void Dispose()
        {
            if (m_sockListener != null)
            {
                m_sockListener.Close();
                m_sockListener = null;
            }
        }

        bool CreateChannel(MxNwkChannelDesc pDesc)
        {
            MxNwkChannel tmpChannel = new MxNwkChannel();	        
	        pDesc.IsEncrypt = m_Desc.m_IsEncrypt;
	        pDesc.LocalType = m_Desc.m_LocalType;
	        pDesc.LocalID = m_Desc.m_LocalID;
	        pDesc.IsClient = false;
            TimeSpan tmpTime = new TimeSpan(DateTime.Now.Ticks);
	        pDesc.CreateTimeSec = tmpTime.Seconds;
        	
	        if(!tmpChannel.Create(pDesc, m_ObsChannel))
	        {		        
		        tmpChannel.Dispose();
                return false;
	        }
            
	        if(tmpChannel.FirstRecv() != true)
	        {
		        return false;
	        }

            MxNetworkManager.GetInstance().AddTmpChannel(tmpChannel);
            return true;
        }
        
        private readonly AsyncCallback m_onAccepted;
        protected MxNwkListenerDesc m_Desc;
        protected MxNwkObsListener m_ObsListener;
        protected MxNwkObsChannel m_ObsChannel;
        protected Socket m_sockListener;
        
    }
}

